#pragma once

#include <types.h>
#include <stddef.h>
#include <gato/color.h>
#include <gato/surface.h>
#include <event.h>

typedef int wid_t;
#define WID_MAX 256
#define WID_INVALID WID_MAX

struct window_config_t
{
    int x, y, width, height;
    uint64_t event_mask;
};

typedef struct window_connect_t
{
    slot_t vmo;
    slot_t event;
    surface_t surface[1];
} window_connect_t;

typedef struct window_t
{
    window_connect_t connect;
    wid_t id;
} window_t;

enum WM_EVENT_TYPE
{
    WM_ABS_EVENT = 1UL << 0,
    WM_KEYDOWN_EVENT = 1UL << 1,
    WM_KEYUP_EVENT = 1UL << 2,
    WM_MOUSEBUTTONDOWN_EVENT = 1UL << 3,
    WM_ROOT_ABS_EVENT = 1UL << 4,
    WM_FLUSH_EVENT = 1UL << 5,
    WM_MOUSE_IN_EVENT = 1UL << 6,
    WM_MOUSE_OUT_EVENT = 1UL << 7,
};

typedef struct wm_event_t
{
    enum WM_EVENT_TYPE type;

    union
    {
        struct
        {
            int x, y;
            int x_root, y_root;
        } abs_event;

        struct
        {
            int code;
        } keydown_event;

        struct
        {
            int code;
        } keyup_event;
        struct
        {
            int x, y;
            int code;
        } mouse_buttondown_event;

        struct
        {
            int x_root, y_root;
        } root_abs_event;
    };
} wm_event_t;

enum WM_REQ
{
    WM_WINDOW_CREATE,
    WM_WINDOW_DESTORY,
    WM_WINDOW_CONFIG_SET,
    WM_WINDOW_CONFIG_GET,
    WM_WINDOW_EVENT_MASK_SET,
    WM_WINDOW_SHOW,
    WM_WINDOW_HIDE,
    WM_WINDOW_UPDATE,
    WM_WINDOW_RAISE,
    WM_WINDOW_MOVE,
};

struct wm_request
{
    enum WM_REQ req;

    union
    {
        struct WM_WINDOW_CREATE_T
        {
            int x;
            int y;
            int width;
            int height;
            color_t bg;
            window_connect_t connect;
        } WM_WINDOW_CREATE;
        struct WM_WINDOW_DESTORY_T
        {
            wid_t id;
        } WM_WINDOW_DESTORY;
        struct WM_WINDOW_CONFIG_SET_T
        {
            wid_t id;
            struct window_config_t config;
        } WM_WINDOW_CONFIG_SET;
        struct WM_WINDOW_CONFIG_GET_T
        {
            wid_t id;
            struct window_config_t config;
        } WM_WINDOW_CONFIG_GET;
        struct WM_WINDOW_EVENT_MASK_SET_T
        {
            wid_t id;
            uint64_t event_mask;
        } WM_WINDOW_EVENT_MASK_SET;
        struct WM_WINDOW_SHOW_T
        {
            wid_t id;
        } WM_WINDOW_SHOW;
        struct WM_WINDOW_HIDE_T
        {
            wid_t id;
        } WM_WINDOW_HIDE;
        struct WM_WINDOW_UPDATE_T
        {
            wid_t id;
        } WM_WINDOW_UPDATE;
        struct WM_WINDOW_RAISE_T
        {
            wid_t id;
        } WM_WINDOW_RAISE;
        struct WM_WINDOW_MOVE_T
        {
            wid_t id;
            int dx;
            int dy;
        } WM_WINDOW_MOVE;
    };
};

#define GET_WM_REQUEST_SIZE(tag) (offsetof(struct wm_request, tag) + sizeof(struct tag##_T))
#define GET_WM_REQUEST(name, tag, ptr) struct tag##_T *name = (&(((struct wm_request *)(ptr))->tag))